package com.roc.jpamysql.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.roc.jpamysql.annotation.SysLog;
import com.roc.jpamysql.dto.res.BaseResponse;
import com.roc.jpamysql.model.LogInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.time.LocalDateTime;

/**
 * wu.peng
 * 2024/3/24 8:05 上午
 *
 * @author rocpeng
 */
@Component
public class SysLogCreator {

    private static Logger logger = LogManager.getLogger(SysLogCreator.class);

    /**
     * 获取接口消耗时间
     *
     * @param pjp
     * @param log
     * @return
     * @throws Throwable
     */
    Object proceedController(ProceedingJoinPoint pjp, LogInfo log) throws Throwable {
        //记录开始接口时间
        long spendTime = System.currentTimeMillis();
        //调用目标接口及获取返回结果
        Object result = pjp.proceed();
        //调用目标接口结束
        //计算接口耗时
        spendTime = (System.currentTimeMillis() - spendTime) / 1000;
        log.setSpendTime(spendTime);
        return result;
    }

    /**
     * 获取返回值
     *
     * @param log
     * @param result
     * @return
     */
    private BaseResponse setResponseCode(LogInfo log, Object result) {
        //判断返回体类型是否为BaseResponse
        if (result != null && result instanceof BaseResponse) {
            BaseResponse restResult = (BaseResponse) result;
            return restResult;
        }
        return new BaseResponse();
    }


    /**
     * 获取请求体
     *
     * @param request
     * @param log
     */
    private void setBody(HttpServletRequest request, LogInfo log) {
        if (request instanceof ContentCachingRequestWrapper) {
            ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
            String body = StringUtils.toEncodedString(
                    wrapper.getContentAsByteArray(),
                    Charset.forName(wrapper.getCharacterEncoding())
            );
            log.setBody(body);
        }
    }

    /**
     * 获取 IP 地址
     *
     * @return
     */
    private String getIpAddress() {
        // 通过RequestContextHolder获取request对象
        HttpServletRequest request = getRequest();
        if (request != null) {
            try {
                return request.getRemoteAddr();
            } catch (Exception e) {
                logger.error("unable to get ip address");
            }
        }
        return null;
    }


    /**
     * 构建日志对象
     */
    LogInfo createOpLog() throws JsonProcessingException {
        HttpServletRequest request = this.getRequest();
        LogInfo log = new LogInfo();
        log.setQuery(request.getQueryString());
        this.setBody(request, log);
        log.setOperateTime(LocalDateTime.now());
        log.setUrl(request.getServletPath());
        log.setIp(getIpAddress());
        return log;
    }

    /**
     * 获取 request 对象
     *
     * @return
     */
    private HttpServletRequest getRequest() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        return request;
    }

    String getLogType(ProceedingJoinPoint pjp) {
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //获取操作
        SysLog sysLog = method.getAnnotation(SysLog.class);
        //获取
        return sysLog.logType().getValue();
    }
}
